namespace Langexplr.Abc

open System.IO
open Langexplr.Abc
open TypeEncodingUtilities


type AbcExceptionInfo =
 {
  eFrom : int;
  eTo : int;
  eTarget : int;
  eExcType : int;
  eVarName : int;
 }
with
   static member ReadFrom(input : BinaryReader) =
     {
        eFrom = int(TypeEncodingUtilities.ReadU30Value(input));
        eTo = int(TypeEncodingUtilities.ReadU30Value(input));
        eTarget = int(TypeEncodingUtilities.ReadU30Value(input));
        eExcType = int(TypeEncodingUtilities.ReadU30Value(input));
        eVarName = int(TypeEncodingUtilities.ReadU30Value(input));
     }
   member this.WriteTo(output : BinaryWriter) =
      TypeEncodingUtilities.WriteU30Value(uint32(this.eFrom),output);
      TypeEncodingUtilities.WriteU30Value(uint32(this.eTo),output);
      TypeEncodingUtilities.WriteU30Value(uint32(this.eTarget),output);
      TypeEncodingUtilities.WriteU30Value(uint32(this.eExcType),output);
      TypeEncodingUtilities.WriteU30Value(uint32(this.eVarName),output);      

end


type AbcMethodBodyInfo( theMethod : int,
                        maxStack : int,
                        localCount : int,
                        initScopeDepth : int,
                        maxScopeDepth : int,
                        code : byte array,
                        exceptions : AbcExceptionInfo array,
                        traits : AbcTraitsInfo array) =
 class
    member this.MethodId
       with get() = theMethod
    member this.MaxStack  with get() = maxStack
    member this.LocalCount  with get() = localCount
    member this.InitScopeDepth  with get() = initScopeDepth
    member this.MaxScopeDepth  with get() = maxScopeDepth
    member this.InstructionBytes with get() = code
    member this.Exceptions  with get() = exceptions
    member this.Traits with get() = traits

    member this.CloneWithMethodId(methodId : int) =
       AbcMethodBodyInfo( methodId,
                          maxStack ,
                          localCount ,
                          initScopeDepth ,
                          maxScopeDepth ,
                          code ,
                          exceptions ,
                          traits ) 
    
       
    static member ReadFrom(input : BinaryReader) =
       let theMethod = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let maxStack = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let localCount = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let initScopeDepth = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let maxScopeDepth = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let codeLength = int(TypeEncodingUtilities.ReadU30Value(input))  in
       let code = input.ReadBytes(codeLength) in      
       let exceptionCount = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let exceptions = [| for _ in 1 .. exceptionCount -> AbcExceptionInfo.ReadFrom(input) |] in
       let traitCount = int(TypeEncodingUtilities.ReadU30Value(input)) in
       let traits = [| for _ in 1 .. traitCount -> AbcTraitsInfo.ReadFrom(input) |] in
       AbcMethodBodyInfo(theMethod, maxStack ,localCount , initScopeDepth , maxScopeDepth ,code ,exceptions, traits)
       
    member this.WriteTo(output : BinaryWriter) =
       TypeEncodingUtilities.WriteU30Value(uint32(theMethod),output);
       TypeEncodingUtilities.WriteU30Value(uint32(maxStack),output);
       TypeEncodingUtilities.WriteU30Value(uint32(localCount),output);
       TypeEncodingUtilities.WriteU30Value(uint32(initScopeDepth),output);
       TypeEncodingUtilities.WriteU30Value(uint32(maxScopeDepth),output);
       TypeEncodingUtilities.WriteU30Value(uint32(code.Length),output);
       output.Write(code);
       TypeEncodingUtilities.WriteU30Value(uint32(exceptions.Length),output);
       Array.iter (fun (e:AbcExceptionInfo) -> e.WriteTo(output)) exceptions;
       TypeEncodingUtilities.WriteU30Value(uint32(traits.Length),output);
       Array.iter (fun (e:AbcTraitsInfo) -> e.WriteTo(output)) traits
       
end
